/*
 * protocol.c
 *
 *  Created on: 2011-7-15
 *      Author: minorityee1984@gmail.com
 *     Purpose:	協議及編解碼接口定義
 */

#include "protocol.h"
#include "err_def.h"
#include "code_engine.h"
#include <assert.h>
#include <string.h>


int pack_msg(Byte* pszBuf, unsigned int uBufLen, unsigned int* puOffset,
		ClientID id, const Message* pstMessage, unsigned int uSizeOfMsg)
{
	assert(NULL != pszBuf);
	assert(NULL != puOffset);
	assert(NULL != pstMessage);
	assert(uBufLen >= uSizeOfMsg);

	// 檢查buf大小是否足夠一個數據包
	if (MAX_PACKED_PKG_SIZE > uBufLen)
	{
		return E_BUF_OVERFLOW;
	}
	// 构造一个数据包頭
	CREATE_PACKAGE_HEADER(pkg, id, *pstMessage);
	// 將數據包頭填充到buf
	memcpy(pszBuf, &pkg, sizeof(pkg));
	pszBuf += PACKED_PKG_DATA_OFFSET;

	// 編碼消息
	int ret = encode_msg(pszBuf, uBufLen, puOffset, pstMessage, uSizeOfMsg);
	if (0 > ret)
	{
		return ret;
	}
	// encode_msg()獲得的偏移量是PackageData(packed)的，因此再加上PackageHeader
	*puOffset += PACKED_PKG_HEADER_SIZE;
	return S_OK;
}

int unpack_msg(const Byte* pszBuf, unsigned int uBufLen,
		unsigned int *puOffset, ClientID *id, Message* pstMessage,
		unsigned int* puSizeOfMsg)
{
	assert(NULL != pszBuf);
	assert(NULL != puOffset);
	assert(NULL != pstMessage);
	assert(NULL != puSizeOfMsg);

	// 檢查buf大小是否足夠一個數據包
	if (uBufLen < PACKAGE_HEADER_SIZE)
	{
		return E_INCOMPLETE_PACKAGE;
	}

	// 獲取數據包頭標識的偏移
	// TODO: 偏移不在首部是否出錯？
	int offset = find_pkg_header_byte(pszBuf, uBufLen);
	if (0 > offset)
	{
		return E_INVALID_PACKAGE;
	}
	//pszBuf偏移到PackageBase頭部
	pszBuf += offset;

	// 獲取數據大小
	*puSizeOfMsg = GET_PACKAGE_SIZE(pszBuf);
	if (*puSizeOfMsg > uBufLen)
	{
		return E_INCOMPLETE_PACKAGE;
	}

	// 獲取ClientID
	*id = GET_CLIENT_ID(pszBuf);

	//pszBuf偏移到PackagData頭部
	pszBuf += PACKED_PKG_DATA_OFFSET;

	//解碼消息
	int ret = decode_msg(pszBuf, uBufLen, puOffset, pstMessage, *puSizeOfMsg);
	if (0 > ret)
	{
		return ret;
	}
	return S_OK;
}

int find_pkg_header_byte(const Byte* pszBuf, unsigned int uBufLen)
{
	unsigned int i = 0;
	for (; i < uBufLen - 1; ++i)
	{
		if (HEAD_BYTE_0 == pszBuf[i] && HEAD_BYTE_1 == pszBuf[i + 1])
			return i;
	}
	return -1;
}
